﻿#if !UNITY_IOS || HUpdate
using System;
using System.IO;
using UnityEngine;
using DownloadTool;
using System.Linq;


namespace UnityModule
{
    //下载任务
    public class DownloadTask
    {
        public enum TaskState
        {
            Waiting,
            Downloading,
            Done,
        }

        public enum RequestMode
        {
            HttpWebRequest,
            WebClient,
            HttpClient,
        }


        public enum emError
        {
            DiskFull,
            VerifyFail
        }
        protected Action<emError> m_onError;
        public event Action<emError> OnError
        {
            add
            {
                m_onError -= value;
                m_onError += value;
            }
            remove
            {
                m_onError -= value;
            }
        }

        /// <summary>
        /// 正在下载的任务数量
        /// </summary>
        public static int RunningTaskNum = 0;

        private Action<string, string> m_callBack;
        public event Action<string, string> Callback
        {
            add
            {
                m_callBack -= value;
                m_callBack += value;
            }
            remove
            {
                m_callBack -= value;
            }
        }

        public void OnComplete(string ab, string exception)
        {
            Action<string, string> callBack = m_callBack;
            m_callBack = null;
            callBack?.Invoke(ab, exception);
        }

        public static int RunMaxCount = 3;
        protected int runCount = 0;

        /// <summary>
        /// 下载进度,子线程回调
        /// 参数一:当前下载的大小
        /// 参数二:总大小
        /// </summary>
        private Action<long, long> m_progress;
        public event Action<long, long> Progress
        {
            add
            {
                m_progress -= value;
                m_progress += value;
            }
            remove
            {
                m_progress -= value;
            }
        }


        //资源名
        public string AbName { get; private set; }
        public AssetBundleInfoV2 AssetBundle { get; private set; }
        //当前状态
        public TaskState State { get; private set; } = TaskState.Waiting;

        public RequestMode Mode { get; set; } = RequestMode.HttpWebRequest;

        public bool ResumeBreakpoint { get; set; }
        //异常
        private string m_exception;

        private long m_bytesReceived = 0;

        private bool m_isHidePriority = false;
        //优先下载
        public bool IsHidePriority
        {
            set
            {
                m_isHidePriority = value;

                if (m_downloadClient != null)
                {
                    m_downloadClient.IsFullSpeed = m_isHidePriority;
                }
            }

            get
            {
                return m_isHidePriority;
            }
        }

        private IDownloadClient m_downloadClient;
        private string Url;
        public DownloadTask(string cdnUrl, AssetBundleInfoV2 assetBundle)
        {
            Url = cdnUrl;
            AssetBundle = assetBundle;
            AbName = assetBundle.abNameWithHash;
        }

        public void Dispose()
        {
            if (m_downloadClient != null)
            {
                //正在下载的任务数量
                RunningTaskNum--;

                //Debug.Log("RunningTaskNum--: " + RunningTaskNum);

                m_downloadClient.Dispose();
                m_downloadClient = null;
            }
        }

        public void Download()
        {
            if (DownloadComponent.IsAppQuit)
            {
                return;
            }
            if (State == TaskState.Done)
            {
                return;
            }
            if (m_downloadClient != null)
            {
                return;
            }
            runCount++;
            if (runCount > RunMaxCount)
            {
                Debug.LogError($"Error Max{SystemInfo.deviceUniqueIdentifier}:{AbName} skip");
                VersionComponent.Instance.ReportFinish(AbName);
                DownloadComponent.Instance.m_failCount++;
                //重试超过最大上限，跳这此资源下载
                OnComplete(AbName, null);
                return;
            }

            State = TaskState.Downloading;
            //正在下载的任务数量
            RunningTaskNum++;
            if(!DownloadClientConfig.IsFullSpeed)
                DownloadClientConfig.ThreadSpeedLimit = DownloadClientConfig.SpeedLimitDefine / RunningTaskNum;


            //Debug.LogError("RunningTaskNum++: " + RunningTaskNum);
            string url = Url + AbName;// + "?" + DateTime.Now.Ticks;
            string savePath = GetSavePath();
            m_downloadClient = new DownloadClient_HttpClient();
            m_downloadClient.IsFullSpeed = m_isHidePriority;
            m_downloadClient.ResumeSupport = ResumeBreakpoint;
            m_downloadClient.Download(url, savePath, DownloadFileCompleted, DownloadProgressChanged);


        }

        /// <summary>
        /// 提升为高优先级, 用于下载需要使用的资源, 只提升
        /// </summary>
        /// <returns>返回是否有变化</returns>
        public bool UpgradePriority()
        {
            if (!m_isHidePriority)
            {
                IsHidePriority = true;
                return true;
            }
            return false;
        }

        private void DownloadProgressChanged(long bytesReceived, long totalBytesToReceive)
        {
            if (DownloadComponent.IsAppQuit)
            {
                return;
            }
            if (m_progress != null)
            {
                //下载变化量
                long diffReceived = bytesReceived - m_bytesReceived;
                m_bytesReceived = bytesReceived;

                //Debug.LogError($"DownloadProgressChanged: {sender}, {bytesReceived}, {totalBytesToReceive}");

                m_progress.Invoke(diffReceived, totalBytesToReceive);
            }
        }

        private void DownloadFileCompleted(Exception error)
        {
            if (DownloadComponent.IsAppQuit)
            {
                return;
            }

            Dispose();

            if (error != null)
            {
                if (error.Message.Contains("Disk full"))
                {
                    VersionComponent.Instance.ReportFinish("Disk full" + AbName);
                    m_callBack?.Invoke(AbName, "Disk full");
                    m_onError?.Invoke(emError.DiskFull);
                }
                else
                {

                    Debug.LogError($"({runCount})DownloadTask DownloadFileCompleted redo download error {Url + AbName}:  {error}");
                    try
                    {
                        File.Delete(GetSavePath());
                    }
                    catch { Debug.LogError($"{SystemInfo.deviceUniqueIdentifier}({runCount}) delete file Fail {AbName} "); }

                    //下载失败, 重新下载
                    Download();
                }
            }
            else
            {
                VerifyFile((succ) =>
                {
                    if (succ)
                    {
                        State = TaskState.Done;
                        //下载成功回调
                        OnComplete(AbName, null);
                    }
                    else {
                        Download();
                    }
                });
             
            }
        }

        protected static readonly byte[] EmptyMd5 = new byte[16];
        protected virtual void VerifyFile(Action<bool> result)
        {
            if (AssetBundle.md5==null|| EmptyMd5.SequenceEqual(AssetBundle.md5))
            {
                result?.Invoke(true);
                return;
            }

            string filePath = GetSavePath();
            if (File.Exists(filePath))
            {
                byte[] md5hash = MD5Utility.FileToMD5(filePath);
                FileInfo fi = new FileInfo(filePath);
                if (md5hash.SequenceEqual(AssetBundle.md5))
                {
                    result?.Invoke(true);
                    return;
                }
                else
                {
                    Debug.LogError($"({runCount}) {filePath}文件验证错误 {md5hash.byteToHexStr()}<>{AssetBundle.md5.byteToHexStr()}");
                    File.Delete(filePath);
                    result?.Invoke(false);
                    return;
                }
            }
            result?.Invoke(false);
        }

        protected string GetSavePath()
        {
            return ApplicationPath.ABCachePath + AbName;
        }
    }
}
#endif